package com.sinosoft.dsp.platform.components.portal.iteration;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.primefaces.event.NodeSelectEvent;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;

import com.sinosoft.dsp.platform.exception.SinoPlatformException;
import com.sinosoft.dsp.system.core.exception.SinoException;
import com.sinosoft.dsp.system.core.log.Log;
import com.sinosoft.dsp.system.utils.Const;

/**
 * 抽象的树形ViewBean
 * 
 * @author 潘巍（PeterPan）
 * @since 2011-5-23 上午09:58:30
 * 
 * @param <T>
 *            树形节点的数据对象
 */
public abstract class SinoAbstractTreeViewBean<T extends ISinoTreeDataObject>
		extends AbstractIterationViewBean<T> implements ISinoTreeViewBean<T> {
	private static final Log log = Log.getLog(SinoAbstractTreeViewBean.class
			.getName());

	// 树形的根节点
	protected DefaultTreeNode rootNode = new DefaultTreeNode("root", null);;

	// 节点Map
	protected Map<String, DefaultTreeNode> nodesMap = new HashMap<String, DefaultTreeNode>();

	// 选择的节点
	protected DefaultTreeNode[] selectedNodes = null;

	protected DefaultTreeNode selectedNode = null;

	// 节点选择的类型
	private SinoTreeSelectNodeType selectionMode;

	// 默认打开的图标
	private String defaultExpandedIcon;

	// 默认收起的图标
	private String defaultCollapsedIcon;

	// 默认叶子节点的图标
	private String defaultLeafIcon;

	// 扩展的树节点的类型
	private List<SinoTreeNodeType> treeNodeType = new ArrayList<SinoTreeNodeType>();

	private DefaultTreeNode currentNode;

	private List<TreeNode> currentNodeHiberarchy = new LinkedList<TreeNode>();

	/**
	 * 构造器方法
	 * 
	 * @throws SinoException
	 */
	@Override
	public void construct(String sceneId, String content) throws SinoException {
		super.construct(sceneId, content);
	}

	@Override
	public DefaultTreeNode getNode(String id) {
		return this.nodesMap.get(id);
	}

	@SuppressWarnings("unchecked")
	@Override
	public T getRow(String id) {
		return (T) getNode(id).getData();
	}

	@Override
	public DefaultTreeNode getRootNode() {
		if (!this.hasLoadFlag) {
			reload();
			this.hasLoadFlag = true;
		}
		return rootNode;
	}

	@Override
	public Map<String, DefaultTreeNode> getNodesMap() {
		return nodesMap;
	}

	@Override
	public void setNodesMap(Map<String, DefaultTreeNode> nodesMap) {
		if (nodesMap != null) {
			this.nodesMap = nodesMap;
		}
	}
	
	public void setReloadFlag(){
		super.setReloadFlag();
		reload();
	}

	protected void reload() {
		clear();
		try {
			if (!loadFromOutset()) {
				List<T> dirList = load();
				if (dirList != null)
					addRows(dirList);
			}
		} catch (Exception e) {
			log.error("加载结构数据出现错误");
		}
	}

	@Override
	public List<T> load() {
		return null;
	}

	/**
	 * 外部设置树
	 * 
	 * @param root
	 * @param nodes
	 */
	@Override
	public boolean loadFromOutset() {
		return false;
	}

	protected void clear() {
		this.rootNode.getChildren().clear();
		this.rootNode.setData(this.getId());
		this.nodesMap.clear();
		this.selectedNodes = null;
		this.selectedNode = null;
		this.currentNode = null;
		this.currentNodeHiberarchy.clear();
	}

	@Override
	public void addRootChild(DefaultTreeNode node) {
		this.setNodeRelation(this.rootNode, node);
	}

	/**
	 * 增加行记录
	 * 
	 * @param t
	 * @throws SinoPlatformException
	 */
	@Override
	public void addRow(T t) throws SinoPlatformException {
		String id = t.getId();
		String pid = t.getParentId();
		if (Const.isEmpty(id)) {
			throw new SinoPlatformException("添加节点的方法要求数据对象必须有ID属性且不能为空。");
		}

		DefaultTreeNode newNode = createNode(t);
		DefaultTreeNode pNode = nodesMap.get(pid);

		// 获得父节点
		if (pNode == null) {
			pNode = rootNode;
		}

		newNode.setParent(pNode);
		pNode.addChild(newNode);

		nodesMap.put(id, newNode);
	}

	/**
	 * 增加节点
	 * 
	 * @param treeList
	 * @throws SinoPlatformException
	 */
	@Override
	public void addRows(List<T> treeList) throws SinoPlatformException {

		T t = null;
		DefaultTreeNode node = null;
		DefaultTreeNode pnode = null;
		int index = 0;
		int maxLoop = treeList.size() * treeList.size();
		while (!treeList.isEmpty() && index < maxLoop) {
			index++;
			t = treeList.remove(0);

			// 如果父为空，设置为一级节点
			if (t.getParentId() == null) {
				if (validateDuplicateNode(t)) {
					throw new SinoPlatformException("数据初始化出现错误，重复添加相同ID节点！");
				}
				node = createNode(t);
				setNodeRelation(rootNode, node);
				nodesMap.put(t.getId(), node);
			}
			// 非根节点
			else {
				pnode = nodesMap.get(t.getParentId());

				// 如果找不到父节点，放回队列
				if (pnode == null) {
					treeList.add(t);
				}
				// 如果有父节点，添加
				else {
					if (validateDuplicateNode(t)) {
						throw new SinoPlatformException("数据初始化出现错误，重复添加相同ID节点！");
					}
					node = createNode(t);
					setNodeRelation(pnode, node);
					nodesMap.put(t.getId(), node);
				}
			}
		}
	}

	private void setNodeRelation(DefaultTreeNode pNode, DefaultTreeNode sNode) {
		sNode.setParent(pNode);
		if (pNode.getData() instanceof ISinoTreeDataObject) {
			ISinoTreeDataObject n = (ISinoTreeDataObject) pNode.getData();
			if (Const.isEmpty(n.getType())) {
				pNode.setType(ISinoTreeDataObject.TREE_TYPE_NODE);
			}
		} else {
			pNode.setType(ISinoTreeDataObject.TREE_TYPE_NODE);
		}

	}

	/**
	 * 创建节点
	 * 
	 * @param t
	 * @return
	 */
	protected DefaultTreeNode createNode(T t) {
		DefaultTreeNode node = new DefaultTreeNode();
		if (Const.isEmpty(t.getType())) {
			node.setType(ISinoTreeDataObject.TREE_TYPE_LEAF);
		} else {
			node.setType(t.getType());
		}
		node.setData(t);
		return node;
	}

	/**
	 * 判断是否是重复节点
	 * 
	 * @param t
	 * @return
	 * @throws SinoPlatformException
	 */
	private boolean validateDuplicateNode(T t) throws SinoPlatformException {
		if (Const.isEmpty(t.getId())) {
			throw new SinoPlatformException("节点ID未指定！");
		}
		return nodesMap.containsKey(t.getId());
	}

	/**
	 * 删除节点
	 * 
	 * @param id
	 * @throws SinoPlatformException
	 */
	@Override
	public void delRow(String id) throws SinoPlatformException {
		delNode(getNode(id));
	}

	/**
	 * 删除节点
	 * 
	 * @param n
	 * @throws SinoPlatformException
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void delNode(DefaultTreeNode n) throws SinoPlatformException {
		try {
			// 删除父引用
			DefaultTreeNode pn = (DefaultTreeNode) n.getParent();
			pn.getChildren().remove(pn);
			// 删除子节点
			delNodeChildren(n);
			// 从Map中删除
			nodesMap.remove(((T) n.getData()).getId());
		} catch (Exception e) {
			throw new SinoPlatformException("删除节点出现错误");
		}
	}

	@Override
	public void delNodeChildren(String id) throws SinoPlatformException {
		delNodeChildren(getNode(id));
	}

	@SuppressWarnings("unchecked")
	@Override
	public void delNodeChildren(DefaultTreeNode n) throws SinoPlatformException {
		try {
			List<TreeNode> tns = n.getChildren();
			if (tns != null) {
				for (TreeNode t : tns) {
					// 删除父引用
					n.getChildren().remove(t);
					// 删除子节点
					delNodeChildren((DefaultTreeNode) t);
					// 从Map中删除
					nodesMap.remove(((T) t.getData()).getId());
				}
			}
		} catch (Exception e) {
			throw new SinoPlatformException("删除子节点出现错误");
		}
	}

	@Override
	public void moveNode(String targetId, String moveId)
			throws SinoPlatformException {
		try {
			DefaultTreeNode target = nodesMap.get(targetId);
			DefaultTreeNode move = nodesMap.get(moveId);
			// 删除父引用
			DefaultTreeNode pmove = (DefaultTreeNode) move.getParent();
			if (pmove != null) {
				pmove.getChildren().remove(move);
			}
			// 添加新的父引用
			target.addChild(move);
			move.setParent(target);
		} catch (Exception e) {
			throw new SinoPlatformException("移动节点出现错误");
		}
	}

	@Override
	public String getDefaultExpandedIcon() {
		if (Const.isEmpty(defaultExpandedIcon)) {
			defaultExpandedIcon = ISinoTreeViewBean.DEFAULT_EXPANDED_ICON;
		}
		return defaultExpandedIcon;
	}

	@Override
	public void setDefaultExpandedIcon(String defaultExpandedIcon) {
		this.defaultExpandedIcon = defaultExpandedIcon;
	}

	@Override
	public String getDefaultCollapsedIcon() {
		if (Const.isEmpty(defaultCollapsedIcon)) {
			defaultCollapsedIcon = ISinoTreeViewBean.DEFAULT_COLLAPSED_ICON;
		}
		return defaultCollapsedIcon;
	}

	@Override
	public void setDefaultCollapsedIcon(String defaultCollapsedIcon) {
		this.defaultCollapsedIcon = defaultCollapsedIcon;
	}

	@Override
	public String getDefaultLeafIcon() {
		if (Const.isEmpty(defaultLeafIcon)) {
			defaultLeafIcon = ISinoTreeViewBean.DEFAULT_LEAF_ICON;
		}
		return defaultLeafIcon;
	}

	@Override
	public void setDefaultLeafIcon(String defaultLeafIcon) {
		this.defaultLeafIcon = defaultLeafIcon;
	}

	@Override
	public List<SinoTreeNodeType> getTreeNodeType() {
		return treeNodeType;
	}

	@Override
	public void addTreeNodeType(SinoTreeNodeType nodeType) {
		if (nodeType != null) {
			if (Const.isEmpty(nodeType.getExpandedIcon())) {
				nodeType.setExpandedIcon(defaultExpandedIcon);
			}
			if (Const.isEmpty(nodeType.getCollapsedIcon())) {
				nodeType.setCollapsedIcon(defaultCollapsedIcon);
			}
			if (Const.isEmpty(nodeType.getIcon())) {
				nodeType.setIcon(defaultLeafIcon);
			}
			this.treeNodeType.add(nodeType);
		}
	}

	@Override
	public boolean isDynamic() {
		return false;
	}

	@Override
	public DefaultTreeNode[] getSelectedNodes() {
		return selectedNodes;
	}

	@Override
	public void setSelectedNodes(DefaultTreeNode[] selectedNodes) {
		this.selectedNodes = selectedNodes;
	}

	@Override
	public DefaultTreeNode getSelectedNode() {
		return selectedNode;
	}

	@Override
	public void setSelectedNode(DefaultTreeNode selectedNode) {
		this.selectedNode = selectedNode;
	}

	@Override
	public String getSelectionMode() {
		if (selectionMode == null) {
			selectionMode = SinoTreeSelectNodeType.SINGLE;
		}
		return selectionMode.getName();
	}

	@Override
	public void setSelectionMode(SinoTreeSelectNodeType selectionMode) {
		this.selectionMode = selectionMode;
	}

	@Override
	public void onNodeSelect(NodeSelectEvent event) {
		setCurrentNode(this.getSelectedNode());
	}

	@Override
	public void changeCurrentNode(String id) {
		setCurrentNode(this.getNode(id));
	}

	@Override
	public void setCurrentNode(DefaultTreeNode node) {
		currentNode = node;
		currentNodeHiberarchy.clear();
	}

	@Override
	public DefaultTreeNode getCurrentNode() {
		if (currentNode == null) {
			currentNode = (DefaultTreeNode) this.getRootNode().getChildren()
					.get(0);
		}
		return currentNode;
	}

	@Override
	public List<TreeNode> getCurrentNodeChildren() {
		if (getCurrentNode() != null) {
			return getCurrentNode().getChildren();
		}
		return null;
	}

	public List<TreeNode> getCurrentNodeHiberarchy() {
		if (currentNodeHiberarchy.size() == 0) {
			if (getCurrentNode() != null) {
				TreeNode ptn = getCurrentNode();
				while (true) {
					if (ptn != null && !(ptn.getData() instanceof String)) {
						currentNodeHiberarchy.add(0, ptn);
						ptn = ptn.getParent();
					} else {
						SinoTreeDataObject data = new SinoTreeDataObject();
						data.setName("root");
						DefaultTreeNode node = new DefaultTreeNode();
						node.setData(data);
						currentNodeHiberarchy.add(0, node);
						break;
					}
				}
			}
		}
		return currentNodeHiberarchy;
	}

}
